#include <stdio.h>
#include <stdlib.h>
#include <config.h>

#include <new>
#include <string>
#include <ios>
#include <iostream>
#include <vector>
#include <stdexcept>
#include <iostream>
#include <cstdlib>

#ifdef HAVE_LIBCGICC
#include <cgicc/Cgicc.h>
#include <cgicc/HTTPHTMLHeader.h>
#include <cgicc/HTMLClasses.h>
using namespace cgicc;
#else
#include <cgi.h>
#endif

#include <assert.h>
#include <mysql.h>

#include "GBConfig.h"
#include "db.h"

using namespace std;

#define LAT_KM_RATIO 111.2
#define LON_KM_RATIO 70.0

static MYSQL conn;

int main(int argc, char **argv)
{
	try {
		float lat = 0;
		float lon = 0;
		float radius = 500;
		int limit = 100;
		char sql[1024];
		MYSQL_RES *sth;
		const char *cfgfile = "/etc/gamebrowser.cfg";
		std::string dbh, dbn, dbu, dbp;

		GBConfig cfg(cfgfile);
		dbh = cfg.getValue("dbhost");
		dbn = cfg.getValue("dbname");
		dbu = cfg.getValue("dbuser");
		dbp = cfg.getValue("dbpass");

		db_setConfig(dbh.c_str(), dbu.c_str(), dbp.c_str(), dbn.c_str());


#ifdef HAVE_LIBCGICC
		Cgicc cgi;
		const_form_iterator val = cgi.getElement("latitude");
		if(val != (*cgi).end() && ! val->isEmpty()) {
			lat = (*val).getDoubleValue();
		}
		val = cgi.getElement("longitude");
		if(val != (*cgi).end() && ! val->isEmpty()) {
			lon = (*val).getDoubleValue();
		}
		val = cgi.getElement("radius");
		if(val != (*cgi).end() && ! val->isEmpty()) {
			radius = (*val).getDoubleValue();
		}
		val = cgi.getElement("limit");
		if(val != (*cgi).end() && ! val->isEmpty()) {
			limit = (*val).getIntegerValue();
		}
#else
		s_cgi *cgi = cgiInit();
		char *pEnd;
		std::string val = cgiGetValue(cgi, "latitude");
		lat = strtod(val.c_str(), &pEnd);

		val = cgiGetValue(cgi, "longitude");
		lon = strtod(val.c_str(), &pEnd);

		val = cgiGetValue(cgi, "radius");
		radius = strtod(val.c_str(), &pEnd);

		val = cgiGetValue(cgi, "limit");
		limit = strtod(val.c_str(), &pEnd);
#endif
		snprintf(sql, 1024, "SELECT server.*, "
				"X(location.location) AS latitude, Y(location.location) AS longitude "
				"FROM server INNER JOIN location USING (ip) "
				"WHERE MBRContains("
				"GeomFromText('Polygon((%0.10f %0.10f,%0.10f %0.10f,%0.10f %0.10f,%0.10f %0.10f,%0.10f %0.10f))') "
				", location.location) ORDER BY avarage DESC, maxplayers DESC LIMIT %i",
				lat-(radius/LAT_KM_RATIO), (lon-radius/LON_KM_RATIO),
				lat-(radius/LAT_KM_RATIO), (lon+radius/LON_KM_RATIO),
				lat+(radius/LAT_KM_RATIO), (lon+radius/LON_KM_RATIO),
				lat+(radius/LAT_KM_RATIO), (lon-radius/LON_KM_RATIO),
				lat-(radius/LAT_KM_RATIO), (lon-radius/LON_KM_RATIO),
				limit
			);

		cerr << "SQL: " << sql << endl;

#ifdef HAVE_LIBCGICC
		cout << HTTPContentHeader("text/xml; charset=utf-8");
#else
		cgiSetType("text/xml; charset=utf-8");
		cgiHeader();
#endif
		cout << "<?xml version='1.0' encoding=\"utf-8\"?>" << endl;
		cout.setf(ios_base::fixed, ios_base::floatfield);
		cout.precision(10);
		cout << "<serverlist>" << endl;
		db_connect(&conn);
		sth = db_doSql(&conn, sql);
		if(sth) {
			MYSQL_ROW row;
			MYSQL_FIELD *fields = mysql_fetch_fields(sth);
			int num_fileds = mysql_num_fields(sth);
			while((row = mysql_fetch_row(sth))) {
				cout << "<server>";
				for(int i=0;i<num_fileds;i++) {
					cout << "<" << fields[i].name << "><![CDATA[";
					cout << row[i];
					cout << "]]></" << fields[i].name << ">";
				}
				cout << "</server>" << endl;
			}
		}
		cout << "</serverlist>" << endl;
		db_close(&conn);
	} catch (const std::exception& e) {
#ifdef HAVE_LIBCGICC
		cout << HTTPHTMLHeader() << HTMLDoctype(HTMLDoctype::eStrict) << endl;
#else
		cgiHeader();
		cout << "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">" << endl;
#endif
		cout << "<html><head></head><body>" << e.what() << "</body></html>" << endl;
	}
	exit(0);
}
